/**
 * dbms-sjtu
 * TableManager.java create @ ����10:07:16
 * @author zhangweipeng
 */
package dbms.metadata;

import java.util.ArrayList;
import java.util.List;

import dbms.Constants;
import dbms.Debug;
import dbms.buffer.Buffer;
import dbms.query.ResultSet;
import dbms.record.RecordPage;
import dbms.record.Schema;
import dbms.record.TableInfo;
import dbms.server.DbmsServer;

/**
 * manager for table, usual operation is
 * <b>create, get information, drop</b>
 * @author zhangweipeng.pt
 */
public class TableManager {
	
	/**
	 * alloc a new page for the new TableInfo object, then write it to database file.
	 * @param tableName
	 * @param tableSchema
	 */
	public static void createTable(String tableName, Schema tableSchema){
		int pageNum = 0;
		/**
		 * set the table's root page, if freePageList is empty, we append this new page to 
		 * database file.
		 */
		if(DbmsServer.freePageList.isEmpty()){
			pageNum = DbmsServer.dataBaseFile.size();
		} else {
			//get page from free page list
			pageNum = DbmsServer.freePageList.remove(0);
			if(!DbmsServer.freePageList.isEmpty()){
				MasterPage.freeListPageNum = DbmsServer.freePageList.get(0);
			} else {
				MasterPage.freeListPageNum = 0;
			}
			
		}
		
		Buffer buffer = new Buffer();
		if((buffer = DbmsServer.bufferManager.findBufferByBlock(pageNum)) ==null){
			buffer = DbmsServer.bufferManager.allocBuffer();
			buffer.connectToBlock(pageNum);
		}

		TableInfo newTable = new TableInfo(tableName, tableSchema);
		buffer.blockNum = -1;
		RecordPage recordPage = new RecordPage(buffer, newTable, 0);
		recordPage.format(buffer.page);
		
		newTable.setFirstPage(pageNum);
		DbmsServer.masterPage.insert(newTable);
		buffer.setInt(Constants.BLOCKSIZE - Constants.INT_SIZE, 0);
		buffer.page.write(pageNum);
		//buffer.page.append();
		buffer.blockNum = pageNum;
	}
	
	public static RecordPage getTableRecordPage(String tableName){
		if(!DbmsServer.masterPage.tableMap.containsKey(tableName)){
			Debug.Error("Table " + tableName + " does not exist.");
			return null;
		} else {
			RecordPage recordPage = DbmsServer.masterPage.tableMap.get(tableName);
			recordPage.initBuffer();
			return recordPage;
		}
	}
	
	/**
	 * get all records data of this table by its tableName
	 * @param tableName
	 * @return result set
	 */
	public static ResultSet getTableData(String tableName){
		if(DbmsServer.masterPage.tableMap.containsKey(tableName)){
			Schema schema = DbmsServer.masterPage.tableMap.get(tableName).table.getTableSchema();
			List<String> fieldList = new ArrayList<String>();
			for(String field : schema.getInfo().keySet()){
				fieldList.add(field);
			}
			//RecordPage recordPage = new RecordPage(buffer, DbmsServer.masterPage.tableMap.get(tableName), 0);
			RecordPage recordPage = DbmsServer.masterPage.tableMap.get(tableName);
			return new ResultSet(schema, recordPage.select(fieldList));
		}
		return null;
	}
	
	/**
	 * DROP TABLE student;
	 * drop table by tablename
	 * 1. get the table's root page, then put this <b>page chain</b> to freePageList<br>
	 * 2. delete this table's record from master table, at page 1<br>
	 * 3. clear the relative information in memory<br>
	 * @param tableName
	 */
	public static void DropTable(String tableName){
		TableInfo delTable = DbmsServer.masterPage.tableMap.get(tableName).table;
		
		//step 1: get the table's root page, then put this <b>page chain</b> to freePageList<br>
		int delPage = delTable.getFirstPage();
		while(delPage != 0){
			Buffer buffer = new Buffer();
			if((buffer = DbmsServer.bufferManager.findBufferByBlock(delPage)) == null){
				buffer = DbmsServer.bufferManager.allocBuffer();
				buffer.connectToBlock(delPage);
			}
			
			if(DbmsServer.freePageList.isEmpty()){
				MasterPage.freeListPageNum = delPage;
			} else {
				int pageNum = DbmsServer.freePageList.get(DbmsServer.freePageList.size() - 1);
				Buffer buffer2;
				if((buffer2 = DbmsServer.bufferManager.findBufferByBlock(pageNum)) == null){
					buffer2 = DbmsServer.bufferManager.allocBuffer();
					buffer2.connectToBlock(pageNum);
				}
				buffer2.setInt(Constants.BLOCKSIZE - Constants.INT_SIZE, delPage);
			}
			DbmsServer.freePageList.add(delPage);
			
			delPage = buffer.getInt(Constants.BLOCKSIZE - Constants.INT_SIZE);
			//release this buffer
			//buffer.blockNum = -1;
			buffer.clear();
		}
		
		//step 2: delete this table's record from master table, at page 1<br>
		DbmsServer.masterPage.delete(delTable.getRowId());
		
		//step 3: clear the relative information in memory<br>
		DbmsServer.masterPage.tableMap.remove(tableName);
	}
}
